﻿using Npoi.Mapper;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Xml.Linq;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using NPOI.SS.UserModel;

namespace JiaofuPaidan
{
    public partial class frmMain : Form
    {
        #region fields
        // 周末、假期
        int[] weeks = new int[] { 6, 0 };
        string[] fangjia;
        string[] shangban;

        // 绑定数据源
        BindingList<Models.ExcelModel> blist;

        /// <summary>
        /// 数据有异常的
        /// </summary>
        List<int> abnormal = new List<int>();
        #endregion

        #region load
        public frmMain()
        {
            InitializeComponent();
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            
        }
        #endregion

        #region 选择文件
        private void btnSelect_Click(object sender, EventArgs e)
        {
            OpenFileDialog file = new OpenFileDialog();
            file.Filter = "Excel 文件|*.xls;*.xlsx|所有文件|*.*";
            
            if (file.ShowDialog() == DialogResult.OK)
            {
                this.txtFile.Text = file.FileName;
                this.dgList.Rows.Clear();
            }
        }
        #endregion

        #region 拖拽事件
        private void frmMain_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.All;
            else
                e.Effect = DragDropEffects.None;
        }

        private void frmMain_DragDrop(object sender, DragEventArgs e)
        {
            string path = ((Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString();
            this.txtFile.Text = path;
        }
        #endregion

        #region 计算事件
        private void btnCompute_Click(object sender, EventArgs e)
        {
            abnormal.Clear();

            // 读取配置信息
            this.getSetting();

            Task.Run(() =>
            {
                this.BeginInvoke(new Action(() =>
                {
                    this.lblState.Text = "正在计算。。。";
                }));

                //Stopwatch sw = new Stopwatch();
                //sw.Start();
                Mapper mapper = null;
                try
                {
                    mapper = new Mapper(this.txtFile.Text);
                }
                catch (Exception ex)
                {
                    this.BeginInvoke(new Action(() =>
                    {
                        this.lblState.Text = ex.Message;
                    }));

                    MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                var list = mapper.Take<Models.ExcelModel>().Select(x => x.Value).ToList();
                list.RemoveAll(x => string.IsNullOrEmpty(x.Code));

                var result = compute(list);
                blist = new BindingList<Models.ExcelModel>(result);

                //sw.Stop();

                this.Invoke(new Action(() =>
                {
                    // 绑定
                    this.dgList.DataSource = blist;

                    // 样式及行号
                    setStyle();

                    //this.lblState.Text = string.Format("完成，共耗时{0}秒", (sw.ElapsedMilliseconds / 1000.0).ToString());
                    this.lblState.Text = "计算完成。 " + (abnormal.Count > 0 ? abnormal.Count + " 条数据有异常" : "");
                }));
            });
        }
        #endregion

        #region 导出
        private void btnExport_Click(object sender, EventArgs e)
        {
            SaveFileDialog save = new SaveFileDialog();
            save.AddExtension = true;
            save.DefaultExt = "xlsx";
            save.Filter = "Excel 文件|*.xls;*.xlsx|所有文件|*.*";

            if (save.ShowDialog() == DialogResult.OK)
            {
                Task.Run(() =>
                {
                    string path = save.FileName;

                    this.BeginInvoke(new Action(() =>
                    {
                        this.lblState.Text = "正在导出。。。";
                    }));

                    var mapper = new Mapper();
                    mapper.Put(blist, "Sheet1");

                    var work = mapper.Workbook;
                    var sheet = work.GetSheet("Sheet1");

                    #region 样式
                    //设置列宽。参数的单位是1/256个字符宽度。 
                    sheet.SetColumnWidth(0, 10*256);
                    sheet.SetColumnWidth(1, 16*256);
                    sheet.SetColumnWidth(2, 18*256);
                    sheet.SetColumnWidth(3, 18*256);
                    sheet.SetColumnWidth(4, 18*256);
                    sheet.SetColumnWidth(5, 50*256);
                    sheet.SetColumnWidth(6, 30*256);
                    #endregion

                    #region 异常数据设置样式
                    // 设置字体
                    ICellStyle style = work.CreateCellStyle();//创建样式对象
                    IFont font = work.CreateFont(); //创建一个字体样式对象
                    //font.FontHeight = 10;
                    //font.FontName = " 宋体";
                    font.Color = new NPOI.HSSF.Util.HSSFColor.Red().Indexed;//颜色参考NPOI的颜色对照表
                    style.SetFont(font);

                    foreach (var index in abnormal)
                        for (int ci=0; ci<7; ci++)
                            sheet.GetRow(index).GetCell(ci).CellStyle = style;
                    #endregion

                    // 保存
                    mapper.Save(path);

                    this.BeginInvoke(new Action(() =>
                    {
                        this.lblState.Text = string.Format("导出完成。路径：{0}", path);
                        //this.lblState.ForeColor = Color.Blue;
                        //this.lblState.Click += (o, a) =>
                        //{
                        //    Process.Start(path);
                        //};
                    }));
                });
            }
        }
        #endregion

        #region 查询
        private void btnQuery_Click(object sender, EventArgs e)
        {
            if (this.blist == null || this.blist.Count <= 0) return;

            var index = this.blist.Select(x => x.Code).ToList().IndexOf(this.txtCode.Text.Trim());

            if (index < 0) return;

            this.dgList.ClearSelection();
            this.dgList.Rows[index].Selected = true;
            this.dgList.CurrentCell = this.dgList.Rows[index].Cells[0];
        }
        #endregion

        #region 设置样式及行号
        void setStyle()
        {
            var color = new Color[] { Color.FromArgb(255, 255, 255), Color.FromArgb(245, 245, 245) };

            var code = "";
            int i = 0;
            foreach (DataGridViewRow row in this.dgList.Rows)
            {
                if (row.IsNewRow) continue;

                if (row.Cells["Code"].Value != null && row.Cells["Code"].Value.ToString() != code)
                {
                    i++;
                    code = row.Cells["Code"].Value.ToString();
                }
                // 行号
                row.HeaderCell.Value = string.Format("{0}", row.Index + 1);

                // 背景色
                row.DefaultCellStyle.BackColor = color[i % 2];
            }

            // 对异常的数据，设置样式
            foreach(var index in abnormal)
            {
                this.dgList.Rows[index-1].DefaultCellStyle.ForeColor = Color.Red;
            }

            this.dgList.Refresh();
        }
        #endregion


        #region 计算
        private List<Models.ExcelModel> compute(List<Models.ExcelModel> list)
        {
            var code = "";
            var rownum = 0; // 行号
            var i = 1; // 不重复行号
            var j = 1; // 重复行号

            var results = new List<string>();
            var current = "";

            foreach (var item in list)
            {
                rownum++;

                if (item == null || item.Code == null || string.IsNullOrEmpty(item.Code.Trim())) continue;

                if (code != item.Code)
                {
                    // 跟上一行不同的编号
                    i++;
                    code = item.Code;

                    // 计算交付时段1和交付时段2
                    if (rownum > 1 && results.Count() > 0)
                    {
                        computeTime(list, results, rownum - 1, j);
                    }

                    // 重置
                    j = 1;
                    results.Clear();
                }
                else
                {
                    // 跟上一行相同的编号
                    j++;
                }

                // 获取当前时段
                current = getCurrent(item, rownum);
                // 设置当前时段
                list[rownum-1].Current = current;

                // 把当前时段添加到列表中
                if (!results.Contains(current) && !string.IsNullOrEmpty(current))
                    results.Add(current);
            }
            
            // 计算最后一个编号的交付时段的内容
            computeTime(list, results, rownum, j);

            return list;
        }
        #endregion

        #region 计算当前时段
        /// <summary>
        /// 计算当前时段
        /// </summary>
        /// <param name="item"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        string getCurrent(Models.ExcelModel item, int index)
        {
            if (!item.Start.ToDate().HasValue || !item.End.ToDate().HasValue) return "";

            var start = item.Start.ToDate().Value;
            var end = item.End.ToDate().Value;

            // 如果结束日期小于开始日期，则结束日期+1天
            if (end < start)
            {
                end = end.AddDays(1);

                // 统计有异常的数据
                abnormal.Add(index);
            }

            var week = (int)item.Start.ToDate().Value.DayOfWeek;
            var month_day = string.Format("{0:00}-{1:00}", start.Month, start.Day);

            if (!this.shangban.Contains(month_day) && (weeks.Contains(week) || this.fangjia.Contains(month_day)))
            {
                return "公休日、法定节假日、调休日";
            }
            else
            {
                if (item.Address.ToUpper().Contains("991_WULUMUQI"))
                {
                    // 新疆
                    // 工作日（10：00-20：00），交替班（20：00-次日10：00）
                    var n10 = DateTime.Parse(start.ToString("yyyy-MM-dd 10:00:00"));
                    var n20 = DateTime.Parse(start.ToString("yyyy-MM-dd 20:00:00"));
                    var n210 = n10.AddDays(1);

                    if (start >= n10 && end <= n20)
                        return "工作日（10:00-20:00）";
                    else if ((start > n20 && end < n210) || (start < n10 && end < n10))
                        return "工作日夜班（20:00-次日10:00）";
                    else if ((start <= n20 && end > n20) || (start < n10 && end >= n10))
                        return "交替班（白连夜）";
                }
                else
                {
                    var n8 = DateTime.Parse(start.ToString("yyyy-MM-dd 08:00:00"));
                    var n1845 = DateTime.Parse(start.ToString("yyyy-MM-dd 18:45:00"));
                    var n28 = n8.AddDays(1);

                    if (start >= n8 && end <= n1845)
                        return "工作日（8:00-18:45）";
                    else if ((start > n1845 && end < n28) || (start < n8 && end < n8))
                        return "工作日夜班（18:45-次日8:00）";
                    else if ((start <= n1845 && end > n1845) || (start < n8 && end >= n8))
                        return "交替班（白连夜）";
                }
            }

            return "";
        }
        #endregion

        #region 合并所有时段，并 计算交付时段
        /// <summary>
        /// 合并所有时段，并 计算交付时段
        /// </summary>
        /// <param name="list"></param>
        /// <param name="results"></param>
        /// <param name="rownum"></param>
        /// <param name="j"></param>
        void computeTime(List<Models.ExcelModel> list, List<string> results, int rownum, int j)
        {
            var concat = string.Join("+", results);
            var delivery = "";
            if (results.Count() == 1)
            {
                delivery = results[0];
            }
            else
            {
                var cats = new string[] {
                    "交替班（白连夜）",
                    "公休日、法定节假日、调休日",
                    "工作日夜班（18:45-次日8:00）",
                    "工作日夜班（20:00-次日10:00）",
                    "工作日（8:00-18:45）",
                    "工作日（10:00-20:00）"
                };

                foreach (var cat in cats)
                {
                    if (results.Contains(cat))
                    {
                        delivery = cat;
                        break;
                    }
                }
                if (delivery == "") delivery = results[0];
            }

            for (var a = 1; a <= j; a++)
            {
                if (list[rownum - a] == null) continue;

                list[rownum - a].Concat = concat;
                list[rownum - a].Delivery = delivery;
            }
        }
        #endregion

        #region 读取节假日
        void getSetting()
        {
            string path = Path.Combine(Application.StartupPath, "setting.xml");

            XElement xel = XElement.Load(path);
            this.fangjia = xel.Element("fangjia").Value.Split(',').Select(x => x.Trim()).Where(x => x != "").ToArray();
            this.shangban = xel.Element("shangban").Value.Split(',').Select(x => x.Trim()).Where(x => x != "").ToArray();
        }
        #endregion
    }
}
/*
此数据是指工程师去现场后反馈的每单的处理时间
说明：
任务编号：是给工程师的派单号
原因：Time-On the Road是指路途时间（包括去程和回程两部分），Time-On the Spot指现场处理时间
服务活动开始/结束时间：是指路途或现场开始/结束时间

举例：
以第一条76260884为例，意思工程师去程是从2018-3-28  08:05:00至2018-3-28  10:08:00
在现场时间是从2018-3-28  11:00:00至2018-3-28  16:00:00
回程时间是从2018-3-28  16:02:00至2018-3-28  18:00:00
以上就是他处理一单所用的所有时间

时间段定义这几种：
公休日、法定节假日、调休日
工作日（8:00-18:45）
工作日夜班（18:45-次日8:00）
交替班（白连夜）
*/
